package ead.cs.web.controller;

import ead.cs.domain.Ship;
import ead.cs.domain.ShipSchedule;
import ead.cs.domain.Shipment;
import ead.cs.domain.User;
import ead.cs.domain.workflow.Status;
import ead.cs.service.*;
import ead.cs.service.workflow.StateMachineHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Controller
@RequestMapping(value = "/back-office/")
public class BackOfficeController {

    @Autowired
    private UserService userService;
    @Autowired
    private ShipService shipService;
    @Autowired
    private ShipScheduleService shipScheduleService;
    @Autowired
    private AlertService alertService;
    @Autowired
    private ShipmentService shipmentService;
    @Autowired
    private StateMachineHandler stateMachineHandler;

    @RequestMapping(method = RequestMethod.GET, value = "dashboard")
    public String redirectDashboard() {
        return "back-office/dashboard";
    }

    @RequestMapping(method = RequestMethod.GET, value = "create-user")
    public String redirectCreateUser() {
        return "back-office/create-user";
    }

    @RequestMapping(method = RequestMethod.POST, value = "create-user")
    public String submitCreateUser(User user) {
        userService.save(user);
        return "back-office/create-user";
    }

    @RequestMapping(method = RequestMethod.GET, value = "create-ship")
    public String redirectShip() {
        return "back-office/create-ship";
    }

    @RequestMapping(method = RequestMethod.POST, value = "create-ship")
    public String submitShip(Ship ship) {
        shipService.save(ship);
        return "back-office/create-ship";
    }

    @RequestMapping(method = RequestMethod.GET, value = "manage-shipment")
    public String redirectManageShipment(String bookingId, Model model) {
        final boolean validBooking;
        if (bookingId == null) {
            validBooking = false;
        } else {
            Shipment shipment = shipmentService.findByPaymentId(bookingId);
            model.addAttribute("shipment", shipment);
            validBooking = shipment != null;
            model.addAttribute("statusList", findByCurrentStatus(shipment.getStatus()));
        }
        model.addAttribute("validBooking", validBooking);
        model.addAttribute("bookingId", bookingId);
        return "back-office/manage-shipment";
    }

    @RequestMapping(method = RequestMethod.POST, value = "manage-shipment")
    public String saveShipment(Shipment shipment) {
        Shipment retrievedShipment = shipmentService.findByPaymentId(shipment.getPayment().getId());
        retrievedShipment.setStatus(shipment.getStatus());
        shipmentService.save(retrievedShipment);

        stateMachineHandler.execute(shipment.getStatus(), retrievedShipment.getId());
        return "back-office/manage-shipment";
    }

    @RequestMapping(method = RequestMethod.GET, value = "create-schedule")
    public String redirectShipSchedule() {
        return "back-office/create-schedule";
    }

    @RequestMapping(method = RequestMethod.POST, value = "create-schedule")
    public String submitShipSchedule(ShipSchedule shipSchedule) throws ParseException {
        shipSchedule.setArrivalDate(formatDate(shipSchedule.getArDate()));
        shipSchedule.setDepartureDate(formatDate(shipSchedule.getDeDate()));
        shipScheduleService.save(shipSchedule);
        return "back-office/create-schedule";
    }

    @RequestMapping(method = RequestMethod.GET, value = "alerts")
    public String showAlerts(Model model) {
        model.addAttribute("alerts", alertService.getBackOfficeAlerts());
        return "back-office/alerts";
    }

    @RequestMapping(method = RequestMethod.GET, value = "reports")
    public String showReports(Model model) {
//        model.addAttribute("re", alertService.getBackOfficeAlerts());
        return "back-office/reports";
    }

    @ModelAttribute(value = "shipList")
    public List<Ship> findAllShips() {
        return shipService.findAll();
    }

    @RequestMapping(method = RequestMethod.GET, value = "ship-tracking")
    public String redirectShipTracking() {
        return "back-office/ship-tracking";
    }

    public List<Status> findByCurrentStatus(Status status) {
        switch (status) {
            case SCHEDULED:
                return addStatus(Status.RECEIVED, Status.CANCELLED);
            case RECEIVED:
                return addStatus(Status.LOADED, Status.REJECTED);
            case LOADED:
                return addStatus(Status.DISPATCHED);
            case DISPATCHED:
                return addStatus(Status.ARRIVED, Status.DISPLACED);
            case ARRIVED:
                return addStatus(Status.UNLOADED, Status.REJECTED);
            case UNLOADED:
                return addStatus(Status.RELEASED);
            default:
                return addStatus(Status.RELEASED);
        }
    }

    private List<Status> addStatus(Status... statuses) {
        return Arrays.asList(statuses);
    }

    private Date formatDate(String dateString) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        return sdf.parse(dateString);
    }
}
